-- Instancias que representan las tablas "users", "verifications" y "profiles".
local userModel     = {}
local Model         = require("lapis.db.model").Model
local db            = require("lapis.db")
local users         = Model:extend("users")
local verifications = Model:extend("verifications")
local profiles      = Model:extend("profiles")


-- Consulta si existe un usuario registrado a partir de su apodo e e-email,
-- y retorna una tabla indexada de usuarios con su id,
-- el estado de activación de cuenta y el tiempo de expiración del token.
function userModel:userFind(username, email)
	local query_str = "SELECT u.id, u.activated, v.expiration AS token_expiration FROM users AS u "..
                      "INNER JOIN verifications AS v ON u.id = v.id "..
                      "WHERE u.username = ? OR u.email = ? LIMIT 2"

	local list_users = db.query(query_str, username, email)

	return list_users
end


-- Elimina un usuario asociado a un id.
function userModel:userDelete(id)
	local user = users:find(id)

	user:delete()
end


-- Registra un usuario.
function userModel:userSave(data)
	local user = users:create({
		name          = data.name,
		username      = data.username,
		email         = data.email,
		password      = data.password,
		creation_date = db.format_date() -- Hora de registro del usuario en UTC.
	})

	-- Obtiene el id del usuario registrado.
	local new_user = users:find({ email = data.email })
	new_user:refresh("id")

	-- Registra la llave y el tiempo de expiración del token.
	local verification = verifications:create({
		id         = new_user.id,
		hash       = data.hash,
		expiration = data.expiration
	})
end


-- Consulta si existe un usuario registrado, dado su columna y el tipo de identificación,
-- y retorna una tabla que contiene el id, el rol, el apodo,
-- la contraseña, el estado de cuenta y el tiempo de expiración del token.
function userModel:userAccess(column, identity)
	local query_str = "SELECT u.id, u.role_id AS role, u.username, u.email, u.password, u.activated, v.expiration AS token_expiration "..
                      "FROM users AS u INNER JOIN verifications AS v ON u.id = v.id "..
                      "WHERE u."..column.." = ? LIMIT 1"

	return db.query(query_str, identity)[1]
end


-- Retorna una tabla con los datos de verificación de un usuario,
-- el estado de activación de cuenta, el id de verificación, la llave de verificación
-- y tiempo de expiración del token.
function userModel:userVerification(email)
	local query_str = "SELECT u.activated, v.id, v.hash AS token_hash, v.expiration AS token_expiration "..
	                  "FROM users AS u INNER JOIN verifications AS v ON u.id = v.id "..
	                  "WHERE u.email = ? AND v.hash IS NOT NULL LIMIT 1"

	return db.query(query_str, email)[1]
end


-- Activa la cuenta de un usuario dado su id. Coloca en 1 su estado de cuenta,
-- en NULL el hash de verificación y en 0 el tiempo de expiración.
function userModel:userActive(id)
	local user = users:find(id)

	user:update({ activated = db.TRUE })

	local verification = verifications:find(id)

	verification:update({ hash = db.NULL, expiration = 0 })

	local profile = profiles:create({ id = id })
end


-- Retorna una tabla con los datos de perfil de un usuario dado su columna y el valor a comparar.
-- Muestra el nombre completo, el apodo, la ruta de su foto de perfil y background y su descripción o autobiografia.
function userModel:userProfile(column, conditional)
	local query_str = "SELECT u.name, u.username, p.avatar_file, p.background_file, p.description "..
	                  "FROM users AS u INNER JOIN profiles AS p ON u.id = p.id "..                  
	                  "WHERE u."..column.." = ? LIMIT 1"

	return db.query(query_str, conditional)[1]
end

--- Consulta si existe un usuario dado su apodo y lo retorna en una tabla.
function userModel:userUsername(username)
	local user = users:find({ username = username })

	if user then
		user:refresh("username")
	end

	return user
end


-- Actualiza los datos personales de un usuario dado su id y las columnas a actualizar.
function userModel:userEdit(id, columns)
	local user = users:find(id)

	user:update(columns)
end


-- Actualiza los datos de un perfil de usuario dado su id y las columnas a actualizar.
function userModel:profileEdit(id, columns)
	local profile = profiles:find(id)

	profile:update(columns)
end


-- Consulta si existe una imagen de perfil o background, dado su columna, y lo retorna en una tabla.
function userModel:imageFind(column, file)
	local profile = profiles:find({ [column] = file }) 

	if profile then
		profile:refresh(column)
	end

	return profile
end


return setmetatable({}, { __index = userModel })